local ffi = require('ffi');
require('platform');
require('lSDL_image');


--跨平台需要实现加载so


ffi.cdef[[
int SDLWritePCM(void*wave,int len);
void SDLSoundCallBack(void*userdata,uint8_t*stream,int len);
]]


local SDL2;
-- SDL2 = ffi.load("SDL2");
-- core = ffi.load('core');
SDL2 = loadso('SDL2');
core = loadso('core');
image = loadso('SDL2_image');
image.IMG_Init(-1);

local tmpbuf = ffi.new('uint8_t[1024]');
local tmpbufint = ffi.cast('uint32_t*',tmpbuf);

local bor = bit.bor

print(SDL2.SDL_Init(-1));

local width = 241;
local height = 160;


GetTick = SDL2.SDL_GetTicks
Delay = SDL2.SDL_Delay
local key = 0;
local keytable = {};

function GetKeyScancode(k)
    local kk = keytable[k];
    if(kk==nil)then
        kk = SDL2.SDL_GetScancodeFromName(k);
        keytable[k] = kk;
    end
    return kk;
end

function GetKeyState(key,...)
    local list = {...};
    if(key)then 
        local state = SDL2.SDL_GetKeyboardState(nil);
        local scode = GetKeyScancode(key);
        if(state[scode]~=0)then
            for k,v in ipairs(list)do
                scode = GetKeyScancode(v);
                if(state[scode]==0)then
                    return;
                end
            end
            return true;
        end
    end
end

function GetGameKey(setValue)
    key = 0;
    local state = SDL2.SDL_GetKeyboardState(nil);
    local function setKeyValue(k,value)
        local kk = GetKeyScancode(k);
        if(state[kk]~=0)then
            key = bor(key,value);
        end
    end
    if(setValue==nil)then
        setKeyValue('a',0x100);
        setKeyValue('s',0x200);
        setKeyValue('z',0x1);
        setKeyValue('x',0x2);
    
        setKeyValue('left',0x20);
        setKeyValue('right',0x10);
        setKeyValue('up',0x40);
        setKeyValue('down',0x80);
        setKeyValue('space',0x4);
        setKeyValue('return',0x8);
    else
        setValue(setKeyValue);
    end
    return key;
end

SDL_PIXELFORMAT_YUY2 = 0x32595559
SDL_PIXELFORMAT_BGR565 = 0x15551002
SDL_PIXELFORMAT_RGBA32 = 0x16762004
SDL_PIXELFORMAT_IYUV = 0x56555949
SDL_PIXELFORMAT_INDEX4LSB = 0x12100400
SDL_PIXELFORMAT_RGB24 = 0x17101803
SDL_PIXELFORMAT_BGR888 = 0x16561804
SDL_PIXELFORMAT_BGRA5551 = 0x15841002
SDL_PIXELFORMAT_BGRX8888 = 0x16661804
SDL_PIXELFORMAT_ABGR1555 = 0x15731002
SDL_PIXELFORMAT_INDEX4MSB = 0x12200400
SDL_PIXELFORMAT_BGR555 = 0x15530F02
SDL_PIXELFORMAT_ARGB8888 = 0x16362004
SDL_PIXELFORMAT_BGRA32 = 0x16362004
SDL_PIXELFORMAT_ARGB32 = 0x16862004
SDL_PIXELFORMAT_UYVY = 0x59565955
SDL_PIXELFORMAT_ABGR4444 = 0x15721002
SDL_PIXELFORMAT_BGR24 = 0x17401803
SDL_PIXELFORMAT_YVYU = 0x55595659
SDL_PIXELFORMAT_ABGR8888 = 0x16762004
SDL_PIXELFORMAT_NV12 = 0x3231564E
SDL_PIXELFORMAT_RGB555 = 0x15130F02
SDL_PIXELFORMAT_RGB565 = 0x15151002
SDL_PIXELFORMAT_NV21 = 0x3132564E
SDL_PIXELFORMAT_YV12 = 0x32315659
SDL_PIXELFORMAT_ABGR32 = 0x16462004
SDL_PIXELFORMAT_ARGB2101010 = 0x16372004
SDL_PIXELFORMAT_BGRA8888 = 0x16862004
SDL_PIXELFORMAT_RGBA8888 = 0x16462004
SDL_PIXELFORMAT_RGBX8888 = 0x16261804
SDL_PIXELFORMAT_BGRA4444 = 0x15821002
SDL_PIXELFORMAT_RGBA4444 = 0x15421002
SDL_PIXELFORMAT_ARGB4444 = 0x15321002
SDL_PIXELFORMAT_RGB444 = 0x15120C02
SDL_PIXELFORMAT_RGB332 = 0x14110801
SDL_PIXELFORMAT_INDEX8 = 0x13000801
SDL_PIXELFORMAT_INDEX1MSB = 0x11200100
SDL_PIXELFORMAT_INDEX1LSB = 0x11100100
SDL_PIXELFORMAT_UNKNOWN = 0x0
SDL_PIXELFORMAT_RGB888 = 0x16161804
SDL_PIXELFORMAT_ARGB1555 = 0x15331002
SDL_PIXELFORMAT_RGBA5551 = 0x15441002

calloc = SDL2.SDL_calloc
new = function(name)
    local size = ffi.sizeof(name);
    --return ffi.new(name);
    return ffi.cast(name..'*',calloc(size,1));
end

local function setDefault(t,name,v)
    if(t[name]==nil)then t[name] = v; end;
end

local function getvalue(dst,name,src)
    if(src[name]~=nil)then dst[name] = src[name]; end;
end

function CreateSound(callback,wantset)
    local want = new('SDL_AudioSpec');
    local have = new('SDL_AudioSpec');
    local  self = {};

    want.freq = 44100;
    want.channels = 2;
    want.samples = 4096;
    -- --want.format = 0x8010;
    want.callback =            --callback是多线程操作,所以不能使用luajit来写入
     core.SDLSoundCallBack;
    
    if(wantset)then
        getvalue(want,'freq',wantset);
        getvalue(want,'channels',wantset);
        getvalue(want,'samples',wantset);
        getvalue(want,'format',wantset);
    end

    
    if(SDL2.SDL_OpenAudio(want,have)<0)then
        print(ffi.string(SDL2.SDL_GetError()));
        assert(nil);
    else
        SDL2.SDL_PauseAudio(0);
    end
    function self:WriteWave(wave,len)
        core.SDLWritePCM(wave,len);
    end
    function self:Pause(v)
        if(v==nil)then v = 0; end;
        SDL2.SDL_PauseAudio(v);
    end

    return self;
end

function SoundPause(v)
    if(v==nil)then v = 0; end;
    SDL2.SDL_PauseAudio(v);
end

function CreateWindow(width,height)
    local window = SDL2.SDL_CreateWindow("游戏",100,100,width,height,bor(SDL2.SDL_WINDOW_OPENGL,SDL2.SDL_WINDOW_SHOWN));
    local event = ffi.new('SDL_Event');
    local srcRect = ffi.new('SDL_Rect');
    local dstRect = ffi.new('SDL_Rect');
    local index = 2; --win32 opengl
    if(ANDROID)then
        index = -1;
    end
    local renderer = SDL2.SDL_CreateRenderer(window,index,bor(SDL2.SDL_RENDERER_TARGETTEXTURE,SDL2.SDL_RENDERER_ACCELERATED));
    texture = SDL2.SDL_CreateTexture(renderer,SDL2.SDL_PIXELFORMAT_ARGB8888,SDL2.SDL_TEXTUREACCESS_STATIC,width,height);
    local wwidth = width;
    local wheight = height;
    local tmp = ffi.new('int[2]');
    SDL2.SDL_GetWindowSize(window,tmp,tmp+1);
    width = tmp[0];
    height = tmp[1];

    --SDL2.SDL_GL_SetSwapInterval(1);
    local self = {};

    self.window = window;
    self.renderer = renderer;
    self.width = width;
    self.height = height;
    self.wwidth = wwidth;
    self.wheight = wheight;

    function self:GetSize()
        return self.wwidth,self.wheight;
    end

    function self:DrawPix32(pix,width,height,x,y,w,h)
        if(x)then
            srcRect.x = x;
            srcRect.y = y;
        else
            srcRect.x = 0
            srcRect.y = 0
        end

        srcRect.w = width;
        srcRect.h = height;
        SDL2.SDL_UpdateTexture(texture,srcRect,pix,4*width);
        if(w)then
            dstRect.x = x;
            dstRect.y = y;
            dstRect.w = w;
            dstRect.h = h;
            SDL2.SDL_RenderCopy(renderer,texture,srcRect,dstRect);
        else
            SDL2.SDL_RenderCopy(renderer,texture,null,null);
        end
    end

    function self:DrawPix16(pix,width,height,x,y,w,h)
        local texture = self.texture16;
        if(texture==nil)then
            local fmt = SDL2.SDL_PIXELFORMAT_BGR555;
            local access = SDL2.SDL_TEXTUREACCESS_TARGET;
            local r = renderer;
            texture = SDL2.SDL_CreateTexture(r,fmt,access,w,h);
            SDL2.SDL_SetTextureBlendMode(texture,SDL2.SDL_BLENDMODE_BLEND);
            self.texture16 = ffi.gc(texture,SDL2.SDL_DestroyTexture);
        end

        srcRect.x = 0
        srcRect.y = 0



        srcRect.w = width;
        srcRect.h = height;

        SDL2.SDL_UpdateTexture(texture,srcRect,pix,2*width);
        if(w)then
            dstRect.x = x;
            dstRect.y = y;
            dstRect.w = w;
            dstRect.h = h;
            SDL2.SDL_RenderCopy(renderer,texture,srcRect,dstRect);
        else
            SDL2.SDL_RenderCopy(renderer,texture,null,null);
        end
    end

    --为了处理设置窗口大小位置
    function self:GetRenderView(width,height,x,y,w,h)
        local view = {};
        view.texture = self.texture16;
        view.dstRect = ffi.new('SDL_Rect');
        view.dstRect.w = w;
        view.dstRect.h = h;
        view.dstRect.x = x;
        view.dstRect.y = y;
        view.srcRect = ffi.new('SDL_Rect',{x=0,y=0,w=width,h=height})
        print(x,y,w,h);
        function view:Render()
            SDL2.SDL_RenderCopy(renderer,self.texture,self.srcRect,self.dstRect);
        end
        function view:GetRenderRect()
            return self.dstRect;
        end
        return view;
    end

    function self:SetVPad(vpad)
        self.vpad = vpad;
    end

    function self:GetGameKey(setValue)
        local key = 0;
        if(not self.vpad)then
            return GetGameKey(setValue);
        else
            return self.key;
        end
        return key;
    end

    function self:KeyState(...)
        return GetKeyState(...);
    end

    function self:RenderClear()
        SDL2.SDL_SetRenderDrawColor(renderer,0,0,0,0);
        SDL2.SDL_RenderClear(renderer);
    end

    function self:SetEventCallBack(func)
        self.event_callback = func;
    end

    function self:GetEventCallBack()
        return self.event_callback;
    end

    ---------------------------------------------------------------------
    --绘制函数
    function self:DrawRect(x,y,w,h,color)
        srcRect.x = x;
        srcRect.y = y;
        srcRect.w = w;
        srcRect.h = h;
        if(color==nil)then
            SDL2.SDL_RenderDrawRect(self.renderer,srcRect);
        else
            SDL2.SDL_GetRenderDrawColor(self.renderer,tmpbuf,tmpbuf+1,tmpbuf+2,tmpbuf+3);
            tmpbufint[1] = color;
            SDL2.SDL_SetRenderDrawColor(self.renderer,tmpbuf[4],tmpbuf[5],tmpbuf[6],tmpbuf[7]);
            SDL2.SDL_RenderDrawRect(self.renderer,srcRect);
            SDL2.SDL_SetRenderDrawColor(self.renderer,tmpbuf[0],tmpbuf[1],tmpbuf[2],tmpbuf[3]);
        end
    end


    -----------------------------------------------------------------------------

    function self:GameLoop(callback)
        if(callback==nil)then callback = function() end; end
        while(true)do
            self.key = 0;
            while(SDL2.SDL_PollEvent(event)~=0)do
                --self:SetTitle(string.format('%X',event.type));
                if(event.type~=0)then
                    if(self.event_callback)then
                        print('aaaaaaaaa');
                        self.event_callback(event);
                    end
                end
                if(not ANDROID and self.vpad)then
                    self.vpad:Event(event);
                end
            end
            if(self.vpad)then
                self.vpad:Event(event);
            end

            local ret = callback(event);
            if(ret~=false)then
                if(self.vpad)then 
                    self.vpad:Render();
                end
            end
            if(event.type==SDL2.SDL_QUIT or self.quit)then
                break;
            end
            SDL2.SDL_RenderPresent(renderer);
        end
    end

    function self:SetTitle(title)
        SDL2.SDL_SetWindowTitle(window,title);
    end

    function self:GameQuit()
        SDL2.SDL_DestroyWindow(window);
        --SDL2.SDL_Quit();
    end

    function self:CreateTexture(w,h)
        local fmt = SDL_PIXELFORMAT_RGBA8888;
        local access = SDL2.SDL_TEXTUREACCESS_TARGET;
        local r = self.renderer;
        local texture = SDL2.SDL_CreateTexture(r,fmt,access,w,h);
        SDL2.SDL_SetTextureBlendMode(texture,SDL2.SDL_BLENDMODE_BLEND);
        return ffi.gc(texture,SDL2.SDL_DestroyTexture);
    end

    function self:LoadImageTexture(fn)
        local surface = image.IMG_Load(fn);
        if(surface==nil)then return nil; end;
        local texture = SDL2.SDL_CreateTextureFromSurface(self.renderer,surface);
        SDL2.SDL_FreeSurface(surface);
        return ffi.gc(texture,SDL2.SDL_DestroyTexture);
    end

    return self;
end


